<template>
  <div class="validate-input-container pb-3">
    <input v-if="tag !== 'textarea'" class="form-control" :class="{ 'is-invalid': inputRef.error }" :value="inputRef.val" @blur="validateInput" @input="updateValue" v-bind="$attrs" />
    <textarea v-else class="form-control" :class="{ 'is-invalid': inputRef.error }" :value="inputRef.val" @blur="validateInput" @input="updateValue" v-bind="$attrs" />
    <span v-if="inputRef.error" class="invalid-feedback">{{ inputRef.message }}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType, reactive, onMounted } from 'vue';
import { emitter } from './ValidateForm.vue';
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
interface RuleProp {
  type: 'required' | 'email' | 'custom';
  message: string;
  validator?: () => boolean;
}
export type RulesProps = RuleProp[];
export type TagType = 'input' | 'textarea';

export default defineComponent({
  props: {
    rules: Array as PropType<RulesProps>,
    modelValue: String,
    tag: {
      type: String as PropType<TagType>,
      default: 'input',
    },
  },
  inheritAttrs: false, // 禁止组件的根元素继承non-props属性（attrs）
  setup(props, ctx) {
    const inputRef = reactive({
      val: props.modelValue || '',
      error: false,
      message: '',
    });

    const updateValue = (e: KeyboardEvent) => {
      const targetValue = (e.target as HTMLInputElement).value;
      inputRef.val = targetValue;
      ctx.emit('update:modelValue', targetValue);
    };

    const validateInput = () => {
      if (props.rules) {
        const allPassed = props.rules.every(rule => {
          let passed = true;
          inputRef.message = rule.message;
          switch (rule.type) {
            case 'required':
              passed = inputRef.val.trim() !== '';
              break;

            case 'email':
              passed = emailReg.test(inputRef.val);
              break;

            case 'custom':
              passed = rule.validator ? rule.validator() : true;
              break;

            default:
              break;
          }
          return passed;
        });
        inputRef.error = !allPassed;
        return allPassed;
      }
      return true;
    };

    onMounted(() => {
      emitter.emit('form-item-created', validateInput);
    });

    return {
      inputRef,
      validateInput,
      updateValue,
    };
  },
});
</script>

<style lang="sass" scoped></style>
